﻿using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using System.Windows.Forms;
using UtilZ.Dotnet.Ex.Communication.Net.Base;
using UtilZ.Dotnet.Ex.Communication.Net.BMQ;
using UtilZ.Dotnet.Ex.Log;

namespace DotnetWinFormApp
{
    public partial class FTestBMQPublisher : Form
    {
        public FTestBMQPublisher()
        {
            InitializeComponent();
        }

        private void FTestBMQPublisher_Load(object sender, EventArgs e)
        {
            try
            {
                var redirectAppenderToUI = (RedirectAppender)Loger.GetAppenderByName(null, "RedirectToUI");
                if (redirectAppenderToUI != null)
                {
                    redirectAppenderToUI.RedirectOuput += RedirectLogOutput;
                }
            }
            catch (Exception ex)
            {
                Loger.Error(ex);
            }
        }

        private void RedirectLogOutput(object sender, RedirectOuputArgs e)
        {
            logControl.AddLog(e.Item.Content, e.Item.Level);
        }

        private void btnClearLog_Click(object sender, EventArgs e)
        {
            logControl.Clear();
        }

        private BMQPublisher _publisher = null;
        private void FTestBMQPublisher_FormClosed(object sender, FormClosedEventArgs e)
        {
            if (this._publisher != null)
            {
                this._publisher.Dispose();
            }
        }

        private void btnInit_Click(object sender, EventArgs e)
        {
            try
            {
                var ip = IPAddress.Parse(txtIp.Text);
                var config = new BMQPublisherConfig()
                {
                    BindEndPoint = new IPEndPoint(ip, (int)numPort.Value),
                    HeartIntervalMilliseconds = 1000 * 1000
                };

                if (checkBoxProtocol.Checked)
                {
                    config.Protocol = NetProtocols.Tcp;
                }
                else
                {
                    config.Protocol = NetProtocols.Udp;
                }
                this._publisher = new BMQPublisher(config);
                Loger.Info("BMQ初始化完成...");
            }
            catch (Exception ex)
            {
                Loger.Error(ex, "BMQ初始化异常");
            }
        }

        private void btmChioceFile_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofd = new OpenFileDialog();
            if (ofd.ShowDialog() == DialogResult.OK)
            {
                txtFilePath.Text = ofd.FileName;
            }
        }

        private void btnPushText_Click(object sender, EventArgs e)
        {
            try
            {
                var message = new BMQTextMessage(100, txtText.Text);
                this._publisher.Push(message);
                Loger.Info("推送数据成功");
            }
            catch (Exception ex)
            {
                Loger.Error(ex, "推送数据异常");
            }
        }

        private void btnPushFile_Click(object sender, EventArgs e)
        {
            try
            {
                string filePath = txtFilePath.Text;
                if (!File.Exists(filePath))
                {
                    Loger.Warn($"文件{filePath}不存在");
                    return;
                }

                Task.Factory.StartNew(this.PushFile, filePath);

            }
            catch (Exception ex)
            {
                Loger.Error(ex, "推送数据异常");
            }
        }

        private void PushFile(object state)
        {
            try
            {
                string filePath = (string)state;
                using (var fs = File.OpenRead(filePath))
                {
                    int length = 40960;
                    byte[] buffer = new byte[length];
                    int sendLen = length;
                    long mod;
                    IBMQDataMessage message;

                    int count = 0;
                    while (fs.Position < fs.Length)
                    {
                        mod = fs.Length - fs.Position;
                        if (mod < length)
                        {
                            sendLen = (int)mod;
                        }

                        fs.Read(buffer, 0, sendLen);
                        if (sendLen < length)
                        {
                            message = new BMQBlobMessage(100, buffer.Take(sendLen).ToArray());
                        }
                        else
                        {
                            message = new BMQBlobMessage(100, buffer);
                        }
                        this._publisher.Push(message);

                        /*******************************************************************************************************************************************************************
                         * 1.udp发送频率过高导致丢包
                         * 很多人会不理解发送速度过快为什么会产生丢包，原因就是UDP的SendTo不会造成线程阻塞，也就是说，UDP的SentTo不会像TCP中的SendTo那样，
                         * 直到数据完全发送才会return回调用函数，它不保证当执行下一条语句时数据是否被发送。（SendTo方法是异步的）这样，
                         * 如果要发送的数据过多或者过大，那么在缓冲区满的那个瞬间要发送的报文就很有可能被丢失。至于对“过快”的解释，
                         * 作者这样说：“A few packets a second are not an issue; hundreds or thousands may be an issue.”（一秒钟几个数据包不算什么，但是一秒钟成百上千的数据包就不好办了）。
                         * 发送方丢包：内部缓冲区（internal buffers）已满，并且发送速度过快（即发送两个报文之间的间隔过短）；  
                         ******************************************************************************************************************************************************************/
                        //Thread.Sleep(10);
                        count++;
                    }

                    Loger.Info($"推送文件完成:{count}");
                }
            }
            catch (Exception ex)
            {
                Loger.Error(ex, "推送文件异常");
            }
        }

        private void btnTestPushPer_Click(object sender, EventArgs e)
        {
            int count = (int)numPer.Value;
            Task.Factory.StartNew(this.Push, count);
        }

        private void Push(object state)
        {
            Stopwatch stopwatch = Stopwatch.StartNew();
            int count = (int)state;
            string msg = @"QT
C++11 标准
时代在变化，C++ 标准也在前进。C++ 正式公布标准有 C++98、C++03、C++11。最新的 C++11 标准是2011年8月12日公布的，在公布之前该标准原名为 C++0x 。这是一次较大的修订和扩充，建议读者专门学一下。

Qt 从 4.8 版本就开始用 C++11 新特性了。编译器里面开始支持 C++11 的版本是 MSVC 2010、GCC 4.5、Clang 3.1，这之后版本的编译器都在逐步完善对 C++11 的支持，现在新版本编译器对新标准的支持都比较全面了。

Qt 官方在编译 Qt5 库的时候都是开启 C++11 特性的，如果我们要在自己项目代码启用新标准，需要在 .pro 文件里面添加一行：
CONFIG += c++11

如果是 Qt4 版本则是添加：";
            var flagMessage = new BMQBlobMessage(99, new byte[] { 1, 2 });
            this._publisher.Push(flagMessage);

            var message = new BMQTextMessage(100, msg);
            for (int i = 0; i < count; i++)
            {
                this._publisher.Push(message);
            }
            stopwatch.Stop();            
            Loger.Info($"push count:{count},耗时:{stopwatch.Elapsed.TotalMilliseconds}毫秒");
            this._publisher.Push(flagMessage);
        }
    }
}
